using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.IO;
using System.Configuration;
using AppSettingsGenerator.Targets;
using CommonGenerator;
using System.Diagnostics;

namespace AppSettingsGenerator.Tests
{
	public class GeneratorTester
	{
		class GeneratorTesterInfo : MarshalByRefObject
		{


			public GeneratorTesterInfo()
			{

			}
			

			Type _GeneratedClass;

			public void Initialize()
			{
				Generator generator = new Generator();
				generator.ConfigFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
				generator.Language = Language.CSharp;
				generator.ClassName = "SomeClass";
				StringWriter writer = new StringWriter();
				generator.WriteClass(writer);
				Microsoft.CSharp.CSharpCodeProvider provider = new Microsoft.CSharp.CSharpCodeProvider();
				var parameters = new System.CodeDom.Compiler.CompilerParameters();
				parameters.ReferencedAssemblies.Add(typeof(ConfigurationManager).Assembly.Location);
				parameters.ReferencedAssemblies.Add(typeof(Uri).Assembly.Location);
				Trace.Write(writer.ToString());
				var result = provider.CompileAssemblyFromSource(parameters, writer.ToString());
				Assert.IsTrue(result.Errors.Count == 0, "error during compilation " + (result.Errors.Count == 0 ? "" : result.Errors[0].ErrorText) + " " + writer.ToString());
				_GeneratedClass = result.CompiledAssembly.GetTypes()[0];
				Assert.AreEqual(generator.ClassName, _GeneratedClass.Name, "incorrect type name");
				Assert.AreEqual(generator.NameSpace, _GeneratedClass.Namespace ?? "", "incorrect namespace");
			}

			public void AssertSettingsAreGenerated()
			{
				var appSettings = _GeneratedClass.GetNestedType("AppSettings");
				Assert.IsNotNull(appSettings, "AppSettings class not generated");
				foreach(string key in ConfigurationManager.AppSettings)
				{
					string value = ConfigurationManager.AppSettings[key];
					var property = appSettings.GetProperty(key);
					if(property == null)
						Assert.Fail(key + " should have been generated");
					Assert.AreEqual(value, property.GetValue(null, null));
				}
			}
			public void AssertConnectionStringsAreGenerated()
			{
				var connectionStrings = _GeneratedClass.GetNestedType("ConnectionStrings");
				Assert.IsNotNull(connectionStrings, "ConnectionStrings class not generated");
				foreach(ConnectionStringSettings setting in ConfigurationManager.ConnectionStrings)
				{
					var property = connectionStrings.GetProperty(setting.Name);
					if(property == null)
						Assert.Fail(setting.Name + " should have been generated");
					Assert.AreEqual(setting, property.GetValue(null, null));
				}
			}
		}

		GeneratorTesterInfo _Inner;
		public GeneratorTester(string path)
		{
			var appDomain = AppDomain.CreateDomain(Guid.NewGuid().ToString(), null, new AppDomainSetup()
			{
				ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
				ConfigurationFile = path
			});
			_Inner = (GeneratorTesterInfo)appDomain.CreateInstanceAndUnwrap(typeof(GeneratorTesterInfo).Assembly.FullName, typeof(GeneratorTesterInfo).FullName);
			_Inner.Initialize();
		}

		public void AssertSettingsAreGenerated()
		{
			_Inner.AssertSettingsAreGenerated();
		}
		public void AssertConnectionStringsAreGenerated()
		{
			_Inner.AssertConnectionStringsAreGenerated();
		}


	}
	[TestClass]
	public class GeneratorTest
	{
		String GetPathToConfig(string confName)
		{
			return "../../../AppSettingsGenerator.Tests/Data/" + confName;
		}

		public GeneratorTester Create(string confName)
		{
			return new GeneratorTester(GetPathToConfig(confName));
		}

		[TestMethod]
		public void SettingsShouldBeGenerated()
		{
			GeneratorTester test = Create("AppSettings.config");
			test.AssertSettingsAreGenerated();
		}

		[TestMethod]
		public void ConnectionStringsShouldBeGenerated()
		{
			GeneratorTester test = Create("ConnectionStrings.config");
			test.AssertConnectionStringsAreGenerated();
		}

		[TestMethod]
		public void ConnectionStringsAnSettingsShouldBeGenerated()
		{
			GeneratorTester test = Create("AppSettingsAndConnectionStrings.config");
			test.AssertConnectionStringsAreGenerated();
			test.AssertSettingsAreGenerated();
		}
	}
}
